package com.github.lzm320a99981e.autocoding.domain.condition;


import com.github.lzm320a99981e.zodiac.component.tools.DateUtils;

import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.github.lzm320a99981e.autocoding.domain.condition.Conditionable.PLACEHOLDER;

/**
 * 条件构造器
 */
public class ConditionsBuilder {
    private ConditionsBuilder() {
    }

    private static final String DEFAULT_DATE_PATTERN = "yyyyMMddHHmmss";
    private static final String DEFAULT_SQL_DATE_PATTERN = "yyyymmddhh24miss";


    private Map<String, Object> conditions = new HashMap<>();
    private String datePattern = DEFAULT_DATE_PATTERN;
    private String sqlDatePattern = DEFAULT_SQL_DATE_PATTERN;


    public static ConditionsBuilder create() {
        return new ConditionsBuilder();
    }

    public ConditionsBuilder datePattern(String datePattern) {
        this.datePattern = datePattern;
        return this;
    }

    public ConditionsBuilder sqlDatePattern(String sqlDatePattern) {
        this.sqlDatePattern = sqlDatePattern;
        return this;
    }

    /**
     * 等于
     *
     * @param column
     * @param value
     * @return
     */
    public ConditionsBuilder eq(String column, Object value) {
        return add(column, value, Conditionable.Operator.EQ);
    }

    /**
     * 不等于
     *
     * @param column
     * @param value
     * @return
     */
    public ConditionsBuilder ne(String column, Object value) {
        return add(column, value, Conditionable.Operator.NE);
    }

    /**
     * 大于等于
     *
     * @param column
     * @param value
     * @return
     */
    public ConditionsBuilder ge(String column, Object value) {
        return add(column, value, Conditionable.Operator.GE);
    }

    /**
     * 大于
     *
     * @param column
     * @param value
     * @return
     */
    public ConditionsBuilder gt(String column, Object value) {
        return add(column, value, Conditionable.Operator.GT);
    }

    /**
     * 小于等于
     *
     * @param column
     * @param value
     * @return
     */
    public ConditionsBuilder le(String column, Object value) {
        return add(column, value, Conditionable.Operator.LE);
    }

    /**
     * 小于
     *
     * @param column
     * @param value
     * @return
     */
    public ConditionsBuilder lt(String column, Object value) {
        return add(column, value, Conditionable.Operator.LT);
    }

    /**
     * 在多个值之中
     *
     * @param column
     * @param iterable
     * @return
     */
    @SuppressWarnings("rawtypes")
    public ConditionsBuilder in(String column, Iterable iterable) {
        return add(column, iterable, Conditionable.Operator.IN);
    }

    /**
     * 不在多个值之中
     *
     * @param column
     * @param iterable
     * @return
     */
    @SuppressWarnings("rawtypes")
    public ConditionsBuilder notIn(String column, Iterable iterable) {
        return add(column, iterable, Conditionable.Operator.NI);
    }

    /**
     * 包含
     *
     * @param column
     * @param value
     * @return
     */
    public ConditionsBuilder like(String column, String value) {
        return add(column, value, Conditionable.Operator.LIKE);
    }

    /**
     * 不包含
     *
     * @param column
     * @param value
     * @return
     */
    public ConditionsBuilder notLike(String column, String value) {
        return add(column, value, Conditionable.Operator.NLIKE);
    }

    /**
     * 左包含
     *
     * @param column
     * @param value
     * @return
     */
    public ConditionsBuilder leftLike(String column, String value) {
        return add(column, value, Conditionable.Operator.LLIKE);
    }

    /**
     * 右包含
     *
     * @param column
     * @param value
     * @return
     */
    public ConditionsBuilder rightLike(String column, String value) {
        return add(column, value, Conditionable.Operator.RLIKE);
    }

    /**
     * 范围值
     *
     * @param column
     * @param min
     * @param max
     * @return
     */
    public ConditionsBuilder between(String column, Object min, Object max) {
        if (Date.class.isAssignableFrom(min.getClass())) {
            conditions.put(column, Conditionable.Operator.BETWEEN.getExpression().replace(PLACEHOLDER + "MIN", toDateSql((Date) min)).replace(PLACEHOLDER + "MAX", toDateSql((Date) max)));
            return this;
        }
        conditions.put(column, Conditionable.Operator.BETWEEN.parseExpression(Arrays.asList(min, max)));
        return this;
    }

    public Map<String, Object> build() {
        return conditions;
    }

    private ConditionsBuilder add(String column, Object value, Conditionable.Operator operator) {
        if (Date.class.isAssignableFrom(value.getClass())) {
            conditions.put(column, toDateCondition((Date) value, operator));
            return this;
        }
        conditions.put(column, operator.parseExpression(value));
        return this;
    }

    private String toDateSql(Date date) {
        return "to_date('" + DateUtils.format(date, datePattern) + "', '" + sqlDatePattern + "')";
    }

    private String toDateCondition(Date date, Conditionable.Operator operator) {
        return operator.getExpression().replace(PLACEHOLDER, toDateSql(date));
    }

}
